﻿using System;
using System.Collections.Generic;
using System.IO;
using Com.AAS.Common.Utils;
using Com.AAS.Toolbox.DataMirror.Server.Handler;
using Com.AAS.Toolbox.DataMirror.Server.Handler.Impl;

namespace Com.AAS.Toolbox.DataMirror.Server
{
    class FileSystemScanHandlerImpl : BaseHandlerImpl, FileSystemScanHandler
    {
        #region FileSystemScanHandler 成员

        public String MonitorPath { get; set; }

        public String[] ImagePaths { get; set; }

        public void DoSync()
        {
            lock (this)
            {
                // 扫描镜像目录下多余的文件
                foreach (String image in ImagePaths)
                {
                    DirectoryInfo imageDirInfo = new DirectoryInfo(image);
                    ScanDirImageDir(imageDirInfo);
                }

                // 扫描监控目录下的文件
                {
                    DirectoryInfo monitorDirInfo = new DirectoryInfo(MonitorPath);
                    ScanDirMonitorDir(monitorDirInfo);
                }
            }
        }

        #endregion

        private void ScanDirMonitorDir(DirectoryInfo rootDirInfo, String rootFullName = null)
        {
            if (rootFullName == null)
                rootFullName = rootDirInfo.FullName;

            if (rootDirInfo.Exists)
            {
                try
                {
                    // 访问权限是控制到路径的
                    FileInfo[] infos = rootDirInfo.GetFiles();
                    foreach (FileInfo fInfo in infos)
                    {
                        String md5 = MD5Util.MD5(fInfo.FullName);
                        if (CheckNeedSychInMonitorDir(fInfo.FullName, rootFullName, md5, ImagePaths))
                        {
                            MonitorEvent e = new MonitorEvent();
                            e.EventType = EventType.DATA_SYNC_UPD;
                            e.EventState = EventState.READY;
                            e.EntityData = new EntityData();

                            e.EntityData.OriginalMonitorPath = rootDirInfo.FullName;
                            e.EntityData.EntityType = EntityType.FILE;
                            e.EntityData.OriginalFullPath = fInfo.FullName;
                            e.EntityData.OriginalName = fInfo.FullName.ToString().Replace(rootFullName + "\\", "");
                            e.EntityData.OriginalMD5Code = md5;
                            OnEventNotie(e);
                            newLogEvent(LogLevel.I, "sync update file : " + fInfo.Name, fInfo.FullName);
                        }
                    }

                    DirectoryInfo[] dirs = rootDirInfo.GetDirectories();
                    for (int i = 0; i < dirs.Length; i++)
                    {
                        ScanDirMonitorDir(dirs[i], rootFullName);
                    }
                }
                catch (UnauthorizedAccessException e)
                {
                    Console.WriteLine(e);
                }
            }
        }

        private bool CheckNeedSychInMonitorDir(String fileFullPath,  String rootPath, String md5, String[] imagePaths)
        {
            if ("N/A".Equals(md5))
                return true;
            else
            {
                String subFullPath = GetSubFullPath(fileFullPath, rootPath);
                foreach (String image in imagePaths)
                {
                    // 通过相对路径获取镜像目录下文件路径
                    FileInfo imageFile = new FileInfo(image + "\\" + subFullPath);
                    if (!imageFile.Exists) // 镜像目录下不存在此文件
                        return true;
                    else
                    {
                        // 镜像目录下存在此文件，但MD5码不一致
                        if (!md5.Equals(MD5Util.MD5(imageFile.FullName)))
                            return true;
                    }
                }
            }
            return false;
        }

        private void ScanDirImageDir(DirectoryInfo rootDirInfo, String rootFullName = null)
        {
            if (rootFullName == null)
                rootFullName = rootDirInfo.FullName;

            if ((rootFullName + "\\.cache").Equals(rootDirInfo.FullName))
                return;

            if (rootDirInfo.Exists)
            {
                FileInfo[] infos = rootDirInfo.GetFiles();
                foreach (FileInfo fInfo in infos)
                {
                    if (CheckNeedSychInImageDir(fInfo.FullName, rootFullName, MonitorPath))
                    {
                        DeleteFile(fInfo, new DirectoryInfo(rootFullName));
                        newLogEvent(LogLevel.I, "sync delete file : " + fInfo.Name, fInfo.FullName);
                    }
                }
                DirectoryInfo[] dirs = rootDirInfo.GetDirectories();
                foreach (DirectoryInfo dir in dirs)
                    ScanDirImageDir(dir, rootFullName);
            }
        }

        private bool CheckNeedSychInImageDir(String fileFullPath, String rootPath, String monitorRootPath)
        {
            String subPath = GetSubFullPath(fileFullPath, rootPath);
            FileInfo monitorFile = new FileInfo(monitorRootPath + "\\" + subPath);
            if (!monitorFile.Exists)
            {
                return true;
            }
            return false;
        }

        private void DeleteFile(FileInfo info, DirectoryInfo parentDir)
        {
            if (!info.Exists)
                return;

            DirectoryInfo backupDirInfo = new DirectoryInfo(parentDir.FullName + "\\.cache");
            if (!backupDirInfo.Exists)
                backupDirInfo.Create();

            FileInfo newFileFullName = new FileInfo(backupDirInfo.FullName + info.FullName.Replace(parentDir.FullName, ""));
            int index = 1;
            while (newFileFullName.Exists)
            {
                String name = newFileFullName.Name;
                String nameTag1 = name;
                String nameTag2 = "";
                int lastIndex = name.LastIndexOf('.');
                if (lastIndex < name.Length - 1)
                {
                    nameTag1 = name.Substring(0, lastIndex);
                    nameTag2 = name.Substring(lastIndex + 1, name.Length - lastIndex - 1);
                }
               newFileFullName = new FileInfo(newFileFullName.DirectoryName + "\\" + nameTag1 + "(" + index + ")" + nameTag2);
            }

            if (!newFileFullName.Directory.Exists)
                newFileFullName.Directory.Create();

            info.MoveTo(newFileFullName.FullName);
        }

        private String GetSubFullPath(String fileFullName, String rootFullName)
        {
            return fileFullName.Replace(rootFullName + "\\", "");
        }

        private void CheckNeedSych(DirectoryInfo root)
        {
            foreach (String image in ImagePaths)
            {
                DirectoryInfo dirTemp = new DirectoryInfo(root.FullName.Replace(MonitorPath, image));
                if (dirTemp.Exists)
                {
                    FileInfo[] infos = dirTemp.GetFiles();
                    foreach (FileInfo fInfo in infos)
                    {
                        FileInfo monitorFile = new FileInfo(fInfo.FullName.Replace(image, MonitorPath));
                        if (!monitorFile.Exists)
                        {
                            // 删除镜像目录下多余的文件
                            // fInfo.Delete();
                            DeleteFile(monitorFile, new DirectoryInfo(image));
                        }
                    }
                }
            }
        }

        private void newLogEvent(LogLevel level, String title, String message)
        {
            OnEventNotie(new MonitorEvent(new LogData(level, title, message)));
        }
    }
}